/*
 * Created on 2005-apr-26
 *
 */
package lab5Source;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Point2D;
import java.util.Iterator;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;

import javax.swing.JApplet;

import lab5Source.S_Message.msgtypes;

/**
 * The class managers the ladybirds on the farm.
 * @author Peter Sunnergren
 */

public class LadyBirdManager extends Thread implements Observer {
	private Vector ladyBirds;
	private LadyBird markedLadyBird;
	private static JApplet applet;
	private static LadyBirdManager instance;
	
	private LadyBirdManager() {
		ladyBirds = new Vector();
	}
	
	/**
	 * Gets an instance of the manager.
	 * @return The manager.
	 */
	public static LadyBirdManager instance() {
		if (null != instance) {
			return instance;
		} else {
			if (null != applet) {
				instance = new LadyBirdManager();
				return instance;
			} else {
				System.out.println("Please init with an applet");
				return null;
			}
		}
	}
	
	/**
	 * Sets the applet and MUST be called before the manager is used for the first time.
	 * @param a The applet.
	 */
	public static void setApplet(JApplet a) {
		applet = a;		
	}	
	
	/**
	 * The tread method that repaints the ladybirds every half second.
	 */
	public void run() {
		while (true) {
			Iterator iter = ladyBirds.iterator();
			while (iter.hasNext()) {
				LadyBird l = (LadyBird)iter.next();
				l.nextAction();
			}
			applet.repaint();
			try {
				Thread.sleep(500);
			} catch( InterruptedException e ) {
				System.out.println("Interrupted Exception caught");
			}
		}
	}
	
	/**
	 * Creates a ladybird.
	 * @return The new ladybird so it can be saved outside the manager.
	 */
	public LadyBird createLadyBird() {
		LadyBird l = new LadyBird();
		/**
		 * Please add code here to remove overlap between them at creation
		 */
		ladyBirds.add(l);
		l.setChanged();
		l.notifyObservers(new S_Message(msgtypes.CHECK_COLLIDE));
		return l;
	}
	
	/**
	 * Removes a ladybird.
	 * @param l The ladybird to be removed.
	 */
	public void removeLadyBird(LadyBird l) {
		ladyBirds.removeElement(l);
	}
	
	/**
	 * Adds a ladybird to the farm.
	 * @param l The ladybird.
	 */
	public void addLadyBird(LadyBird l) {
		ladyBirds.add(l);
	}
		
	/**
	 * Marks the ladybird at the position described by x and y. If there is not any ladybird at position or the ladybird is the same as the old marked ladybird the marked ladybird variable is set to null.
	 * @param x X coordinate of position.
	 * @param y Y coordinate of position.
	 */
	public void markLadyBirdAt(int x, int y) {
		Iterator iter = ladyBirds.iterator();
		while (iter.hasNext()) {
			LadyBird l = (LadyBird)iter.next();
			if (Point2D.distance(l.getX(), l.getY(), x, y) < l.getSize()) {
				if (markedLadyBird != l) {
					markedLadyBird = l;
					return;
				}
			}
		}
		markedLadyBird = null;
	}
	
	/**
	 * 
	 * Decides if there is a ladybird at the position described by x and y.
	 * @param x X coordinate of position.
	 * @param y Y coordinate of position.
	 * @return True if it is one there.
	 */
	public boolean isLadyBirdAt(int x, int y) {
		Iterator iter = ladyBirds.iterator();
		while (iter.hasNext()) {
			LadyBird l = (LadyBird)iter.next();
			if (Point2D.distance(l.getX(), l.getY(), x, y) < l.getSize()) {
					return true;
			}
		}		
		return false;
	}
	
	/**
	 * Gets the marked ladybird.
	 * @return The marked ladybird.
	 */
	public LadyBird getMarkedLadyBird() {
		return markedLadyBird;
	}
	
	/**
	 * Draws the ladybirds and a white ring around the marked ladybird.
	 * @param g Graphics.
	 */
	public void paint(Graphics g) {
		Iterator iter = ladyBirds.iterator();
		while (iter.hasNext()) {
			((LadyBird)iter.next()).paint(g);
		}
		
		if (null != markedLadyBird) {
			Graphics2D g2 = (Graphics2D)g;
			g2.setColor(Color.white);
			g2.setStroke(new BasicStroke(2));
			g2.drawOval(markedLadyBird.getX() - markedLadyBird.getSize() + 1,
					markedLadyBird.getY() - markedLadyBird.getSize() + 1,
					2*markedLadyBird.getSize() - 1, 2*markedLadyBird.getSize() - 1);
		}
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		S_Message msg = (S_Message) arg1;

		if (msg.type.equals(msgtypes.CHECK_COLLIDE)) {
			this.S_checkCollide((LadyBird) arg0);
		} else if (msg.type.equals(msgtypes.UPDATE_SIZE)){
			this.S_updateSize((LadyBird) arg0);
		} else if (msg.type.equals(msgtypes.UPDATE_COLOR)) {
			this.S_updateColor((LadyBird) arg0);
		} else {
			System.out.println("Error: unknown message received in LadyBirdManager.update()");
		}
		
	}
	
	private void S_checkCollide(LadyBird lady) {
		int idx = this.ladyBirds.indexOf(lady);
		
		for (int i=0; i < this.ladyBirds.size(); i++) {
			if (i != idx) {
				lady.collide((LadyBird)this.ladyBirds.get(i));
			}
		}
	}
	
	private void S_updateSize(LadyBird lady) {
		int idx = this.ladyBirds.indexOf(lady);		
		for (int i=0; i < this.ladyBirds.size(); i++) {
			if (i != idx) {
				int size = lady.getSize();
				LadyBird currentLady = (LadyBird) this.ladyBirds.get(i);
				currentLady.setSize(size);				
			}
		}
	}
	
	private void S_updateColor(LadyBird lady) {
		int idx = this.ladyBirds.indexOf(lady);
		
		for (int i=0; i < this.ladyBirds.size(); i++) {
			if (i != idx) {
				Color color = lady.getColor();
				LadyBird currentLady = (LadyBird) this.ladyBirds.get(i);
				currentLady.setColors(color, currentLady.getDotColor());
			}
		}
	}
	
	public void S_setRandomGoal(LadyBird lady) {
		int x, y;
		x = (int) (Math.random() * ((FarmApplet.MAXX)-2*lady.getSize())) + lady.getSize();
		y = (int) (Math.random() * ((FarmApplet.MAXY)-2*lady.getSize())) + lady.getSize();
		
		lady.setGoal(x, y);
	}
} // class
